1. Field of the Invention
This invention relates in general to the field of memory segmentation, and more particularly to an improved method and apparatus for loading a segment register within a processing system.
2. Description of the Related Art
Memory management is a hardware mechanism which lets operating systems create simplified environments for running programs. For example, when several programs are running at the same time, they must each be given an independent address space. If they all had to share the same address space, each would have to perform difficult and time consuming checks to avoid interfering with the others.
Memory management consists of two methodologies called segmentation and paging. Segmentation is used to give each program several independent, protected address spaces. Paging is used to support an environment where large address spaces are simulated using a small amount of RAM and some disk storage. When several programs are running at the same time, either mechanism can be used to protect programs against interference from other programs. The following discussion will focus on segmentation.
Segmentation organizes memory into a collection of variable-size units, called segments. Within x86 processors, a two-part address is utilized: a segment part and an offset part. For a general background on segmentation in x86 processors, please see U.S. Pat. No. 4,442,484 issued to Childs, Jr. et al. The first part of the address, the segment part, defines a base address for a segment, and the offset defines a particular memory location which is offset from the base address.
To access data within a given memory segment, a program must first load a segment register with a special value that identifies that segment. This special value is called a selector. Programs then reference memory by specifying, either implicitly, explicitly, or by default, the segment register containing the selector for the segment part of the address. When a selector is referenced, it is used to determine the base address for the segment. The base address is then added to the offset to form the linear address for the memory location to be accessed.
More specifically, the selector is used to index into one of a number of descriptor tables which contain, descriptors. Descriptors define a base address for each segment, the largest offset that can be used with the segment (the limit), and various attributes of the segment such as whether the segment can be read from, written to, or executed as a program, the privilege level of the segment, etc. In an x86 environment, two descriptor tables are provided: 1) the Global Descriptor Table (GDT); and 2) the Local Descriptor Table (LDT). A third descriptor table (IDT) is provided for interrupt routines, but will be ignored for purposes of the present discussion. Each of the descriptor tables can contain up to 8,192 descriptors corresponding to 8,192 possible segments within memory. The descriptor tables are stored in memory.
The selector is a 16-bit value. Bits 3-15 of the selector, termed the descriptor index, define one of the 8,192 descriptors within one of the two descriptor tables. Bit 2, termed the table index (TI), selects which of the two tables, GDT or LDT, contains the descriptor of interest. Bits 0-1 contain the requested privilege level of the access.
As mentioned above, to access a particular memory segment, a program must first load a selector which identifies the segment into a segment register. Commensurate with the loading of the selector, the descriptor which defines the segment is loaded into a hidden or shadow register termed the descriptor register, which is associated with the segment register. Future references to the segment can then utilize the base address, limit, and attributes of the segment by retrieving the descriptor directly from the segment register, without requiring access to one of the two descriptor tables in memory.
When loading a segment register with a selector, and its associated descriptor, the selector is first loaded into a temporary register. The content of the TI bit is then extracted to determine which of the two descriptor tables, GDT or LDT, contains the descriptor to be loaded. Once the value of the TI bit is determined, the appropriate descriptor table is referenced to retrieve the descriptor for the memory segment. The descriptor is then stored in the shadow descriptor register, and the selector is written from the temporary register into the segment register. Thus, each time a segment register is loaded, at least three steps are required: 1) load the selector into a temporary register; 2) extract the TI bit to determine whether the descriptor is in the GDT or LDT; and 3) load the descriptor/selector into the segment register.
Hardware implementations of memory segmentation utilize a limited number of segment registers for storing selectors/descriptors. The segment registers allow programs to calculate memory locations for different segments, without having to reload the segment registers from memory. However, with over 16,000 possible memory segments, it is frequently necessary to overwrite previously used selector/descriptor information in the segment registers with new selector/descriptor information. And, each time access to a new memory segment is desired, program processing is delayed until the new selector/descriptor information can be loaded from memory into a segment register.
In the prior art, loading of a selector/descriptor into a segment register required at least three steps before access to the memory segment could be performed. As mentioned above, one of these steps includes determining which of the two descriptor tables contains the descriptor of interest, i.e., extracting the TI bit from the selector. One method which has been used performs a bit test on the selector to determine whether the TI bit selects the GDT or the LDT. A branch to one of two descriptor routines is then performed based on the outcome of the bit test. But, performing a bit test, and then a branch creates costly processing delays during program execution.
A second method used to determine whether the LDT or GDT is referenced by a selector is to extract the TI bit during the selector load, and feed the extracted bit back into the address operand of the following instruction. However, prior to multiplexing ("muxing") in the TI bit, the following instruction needs to be decoded to determine whether or not the TI bit should in fact be multiplexed into the register address. If a descriptor load instruction follows a selector load instruction, then mux it in. If a descriptor load instruction does not follow extracting the TI bit, then do not mux it in. However, the instruction decode to determine whether the following instruction was a descriptor load also required valuable processing time.
What is needed is a an apparatus and method which minimizes delays associated with the loading of a selector/descriptor into a segment register. More specifically, what is needed is a mechanism which eliminates the processing delay associated with determining which descriptor table contains the descriptor to be loaded into the segment register.